﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DealFile;
using System.Threading;
using BasicClass;
using System.Diagnostics;
using System.IO;


namespace DealPLC
{
    public class PortPLC_PanModbusTCP : BasePortPLC
    {
        #region 定义
        string NameClass = "";

        Mutex g_MtWrite = new Mutex();

        ModBusTCP ModBusSocket = null;
        #endregion 定义

        #region 初始化
        public PortPLC_PanModbusTCP()
        {
            NameClass = "PortPLC_PanModbusTCP";
        }
        #endregion 初始化

        #region 连接PLC
        //打开通信接口
        public override bool OpenPLC(out string error)
        {
            try
            {
                ModBusSocket = new ModBusTCP(ParSetPLC.P_I.IP, (ushort)ParSetPLC.P_I.Port, out error);

                return (bool)ModBusSocket?.Connected;
            }
            catch (Exception ex)
            {
                error = ex.Message;
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
        }

        //关闭通信接口
        public override bool ClosePLC()
        {
            try
            {
                ModBusSocket?.Dispose();
                return true;
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
        }
        #endregion 连接PLC

        #region 读取寄存器
        public override bool ReadReg(string reg, out int intValue)
        {
            //全局使用同一个互斥体
            g_MtWrite.WaitOne();
            intValue = 0;
            try
            {
                bool blResult = ModBusSocket.ReadSingleReg(reg, ref intValue);
                return blResult;
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
            finally
            {
                g_MtWrite.ReleaseMutex();
            }
        }

        /// <summary>
        /// 读取批量寄存器
        /// </summary>
        /// <param name="reg">批量寄存器</param>
        /// <param name="intNum">读取个数</param>
        /// <param name="intValue">输出数组</param>
        /// <returns></returns>
        public override bool ReadBlockReg(string reg, int intNum, out int[] intValue)
        {
            //全局使用同一个互斥体
            g_MtWrite.WaitOne();
            intValue = new int[intNum];
            try
            {
                bool blResult = ModBusSocket.ReadMultReg(reg.Split('\n')[0], intNum,ref intValue);
                return blResult;
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
            finally
            {
                g_MtWrite.ReleaseMutex();
            }
        }

        /// <summary>
        /// 连续的寄存器
        /// </summary>
        public override bool ReadBlockReg_Continue(string reg, int intNum, out int[] intValue)
        {
            //全局使用同一个互斥体
            g_MtWrite.WaitOne();
            intValue = new int[intNum];
            try
            {
                //只传入首地址
                bool blResult = ModBusSocket.ReadMultReg(reg.Split('\n')[0], intNum,ref intValue);
                return blResult;
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
            finally
            {
                g_MtWrite.ReleaseMutex();
            }
        }
        #endregion 读取寄存器

        #region 写入寄存器
        public override bool WriteReg(string reg, int intValue, string strFunName)
        {
            //全局使用同一个互斥体
            g_MtWrite.WaitOne();
            try
            {
                if (RegeditPLC.R_I.BlOffLinePLC)//不写入PLC
                {
                    LogPLC.L_I.WritePLC("PLCWrite", "PLC离线");
                    return true;
                }
                int intState = 0;
                Stopwatch sw_WritePLC = new Stopwatch();
                sw_WritePLC.Start();

                ModBusSocket.WriteSingleReg(reg.Split('\n')[0], intValue);

                if (ParSetPLC.P_I.regHeartBeat != reg)//不记录心跳的写入
                {
                    sw_WritePLC.Stop();
                    LogPLC.L_I.WritePLC(NameClass, strFunName, reg.Replace("\n", ",").PadLeft(7, ' '), intValue.ToString(), sw_WritePLC.ElapsedMilliseconds.ToString());
                }

                if (intState != 0)
                {
                    Log.L_I.WriteError(NameClass + "Error", "WriteReg", intState.ToString());
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
            finally
            {
                g_MtWrite.ReleaseMutex();
            }
        }

        //写入批量寄存器
        public override bool WriteBlockReg(string reg, int intNum, int[] intValues, string strFunName)
        {
            //全局使用同一个互斥体
            g_MtWrite.WaitOne();
            try
            {
                if (RegeditPLC.R_I.BlOffLinePLC)//不写入PLC
                {
                    LogPLC.L_I.WritePLC(NameClass, "PLC离线");
                    return true;
                }
                int intState = 0;
                Stopwatch sw_WritePLC = new Stopwatch();
                sw_WritePLC.Start();
                //写入
                ModBusSocket.WriteMultReg(reg.Split('\n')[0], intValues);

                sw_WritePLC.Stop();
                if (ParSetPLC.P_I.regHeartBeat != reg)//不记录心跳的写入
                {
                    string strValue = "";
                    try
                    {
                        for (int i = 0; i < intNum / 2; i++)
                        {
                            strValue += (ConvertData(intValues[2 * i], intValues[2 * i + 1])).ToString() + ",";
                        }
                        if (intNum % 2 == 0)
                        {

                        }
                        else
                        {
                            strValue += intValues[intNum - 1].ToString();
                        }

                        LogPLC.L_I.WritePLC(NameClass + "Write", strFunName + "-the reg must be continuous", reg.Replace("\n", ","), strValue, sw_WritePLC.ElapsedMilliseconds.ToString());
                    }
                    catch
                    {

                    }
                }

                if (intState != 0)
                {
                    Log.L_I.WriteError(NameClass + "Error", "WriteReg", intState.ToString());
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return false;
            }
            finally
            {
                g_MtWrite.ReleaseMutex();
            }
        }
        [Obsolete]
        public override bool WriteBlockReg(string reg, int[] intValue)
        {
            return false;
        }
        #endregion 写入寄存器

        int ConvertData(int[] value)
        {
            try
            {
                Byte[] byarrTemp;
                Byte[] byarrBufferByte = { 0, 0, 0, 0 };
                for (int i = 0; i < 2; i++)
                {
                    byarrTemp = BitConverter.GetBytes(value[i]);
                    byarrBufferByte[i * 2] = byarrTemp[0];
                    byarrBufferByte[i * 2 + 1] = byarrTemp[1];
                }
                return BitConverter.ToInt32(byarrBufferByte, 0);
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return 0;
            }
        }
        double ConvertData(int value1, int value2)
        {
            try
            {
                int[] value = new int[2];
                value[0] = value1;
                value[1] = value2;
                return (double)ConvertData(value);
            }
            catch (Exception ex)
            {
                Log.L_I.WriteError(NameClass, ex);
                return 0;
            }
        }
    }
}
